package com.lz.netty.producer.project.netty;

import com.lz.netty.producer.project.netty.config.ServerProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;


/**
 * 虫洞栈：https://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * Create by fuzhengwei on 2019
 * @author Administrator
 */

@Component
@Slf4j
@RequiredArgsConstructor
public class NettyServer {

    private final ServerProperties serverProperties;

    /**
     * 启动 netty服务端
     * */
    @PostConstruct
    public void start() throws Exception {
        bing(serverProperties.getPort());
    }

    private static void bing(int port) {
        //EventLoopGroup 是处理 I/O 操作的核心，它包含一个或多个 EventLoop。每个 EventLoop 都是一个不断运行的事件循环，负责处理所有的 I/O 事件，并顺序地处理所有的任务，保证线程安全。
        //配置服务端NIO线程组
        //NioEventLoopGroup extends MultithreadEventLoopGroup Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
        //1、创建 EventLoopGroup：这通常包括一个 Boss Group（用于接收连接）和一个 Worker Group（用于处理 I/O）。
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //2、创建 ServerBootstrap：这是配置服务器的起点
            ServerBootstrap b = new ServerBootstrap();
            //3、配置 ServerBootstrap：设置选项（如 childOption）、处理器（如 ChannelInitializer）等
            b.group(bossGroup, workerGroup)
                    //Channel 是 Netty 网络通信的组件，它类似于传统 IO 中的 Socket。Channel 提供连接的 socket 和读写操作。根据传输方式的不同（如 NIO、OIO 等），有不同的 Channel 实现，如 NioSocketChannel、NioServerSocketChannel 等。
                    //非阻塞模式
                    .channel(NioServerSocketChannel.class)
                    // tcp缓冲区
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 将网络数据积累到一定的数量后,服务器端才发送出去,会造成一定的延迟。希望服务是低延迟的,建议将TCP_NODELAY设置为true
                    .childOption(ChannelOption.TCP_NODELAY, false)
                    // 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //4、处理连接和业务逻辑：在 ChannelInitializer 中添加自定义的 ChannelHandler 来处理连接和业务逻辑。
                    .childHandler(new MyChannelInitializer());
            log.info("服务端开始启动成功");
            //5、绑定端口：调用 bind() 方法绑定端口并启动服务器。
            ChannelFuture f = b.bind(port).sync();
            log.info("服务端启动成功");
            //f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("服务端启动失败：", e.getMessage());
            //childGroup.shutdownGracefully();
            //parentGroup.shutdownGracefully();
        } finally {
            //childGroup.shutdownGracefully();
            //parentGroup.shutdownGracefully();
            log.info("服务端启动完成");
        }

    }

}

